package gatperdut.chato.core.item;

import gatperdut.chato.constants.CSConstantsFood;
import gatperdut.chato.constants.CSConstantsString;
import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.core.item.inventory.BoxInventoryController;
import gatperdut.chato.core.item.inventory.InventoryController;
import gatperdut.chato.core.keywords.KeywordsController;
import gatperdut.chato.core.util.LockController;
import gatperdut.chato.model.Chato.Constant.Fluid;
import gatperdut.chato.model.Chato.Constant.WearLoc;
import gatperdut.chato.model.Chato.Item.Item;

public class ItemController {

    private final Item item;

    private final ChatoServer chatoServer;

    private final KeywordsController keywordsController;

    private InventoryController containerController;

    private final InventoryController inventoryController;

    private final AmountController amountController;

    private final LockController lockController;

    private final WearController wearController;

    public ItemController( ChatoServer chatoServer, Item item ) {
        this.item = item;
        this.chatoServer = chatoServer;
        getChatoServer().getItemHandler().registerItem( getItem(), this );

        keywordsController = new KeywordsController( item.getKeywords() );

        if ( item.getInventory() != null ) {
            inventoryController = new BoxInventoryController( getChatoServer(), item.getInventory() );
            if ( item.getInventory().getLock() != null ) {
                lockController = new LockController( item.getInventory().getLock() );
            }
            else {
                lockController = null;
            }
        }
        else {
            inventoryController = null;
            lockController = null;
        }

        if ( item.getDrink() != null ) {
            amountController = new DrinkController( item.getDrink() );
        }
        else if ( item.getFood() != null ) {
            amountController = new FoodController( item.getFood() );
        }
        else if ( item.getStack() != null ) {
            amountController = new StackController( item.getStack() );
        }
        else {
            amountController = null;
        }

        if ( item.getWear() != null ) {
            wearController = new WearController( item.getWear() );
        }
        else {
            wearController = null;
        }
    }

    public boolean isDrinkable() {
        return getItem().getDrink() != null;
    }

    public boolean isEatable() {
        return getItem().getFood() != null;
    }

    public boolean isStackable() {
        return getItem().getStack() != null;
    }

    public boolean isStorage() {
        return getItem().getInventory() != null;
    }

    public boolean isLockable() {
        return getItem().getInventory().getLock() != null;
    }

    public boolean isWearable() {
        return getItem().getWear() != null;
    }

    public WearLoc getFirstWearLoc() {
        return getWearController().getFirstWearLoc();
    }

    public String getFullDesc() {
        StringBuilder sb = new StringBuilder( getItem().getFullDesc() );
        if ( isWearable() ) {
            sb.append( CSConstantsString.NEWLINE );
            sb.append( "You recognize you could wear it in your " );
            sb.append( getWearController().listWearLocations() );
        }
        return sb.toString();
    }

    public String getShortDesc() {
        return getShortDesc( false );
    }

    public String getShortDesc( boolean showDrinkableContents ) {
        if ( isEatable() ) {
            FoodController fc = (FoodController) getAmountController();
            if ( fc.getCurrent() == 1 ) {
                return CSConstantsFood.getEdibleLeftovers( fc.getPortion(), fc.getMaxPortion() ) + " " + getItem().getShortDesc();
            }
            else {
                return getItem().getShortDesc() + " (x" + fc.getCurrent() + ", " + CSConstantsFood.getEdibleLeftoversLabel( fc.getPortion(), fc.getMaxPortion() ) + ")";
            }
        }

        if ( isDrinkable() ) {
            DrinkController dc = (DrinkController) getAmountController();
            StringBuilder sb = new StringBuilder( " (" );
            if ( dc.getCurrent() > 1 ) {
                sb.append( "x" + dc.getCurrent() );
            }
            if ( !showDrinkableContents ) {
                if ( dc.getCurrent() > 1 ) {
                    return getItem().getShortDesc() + sb.toString() + ")";
                }
                else {
                    return getItem().getShortDesc();
                }
            }
            else if ( dc.hasNoPortionLeft() ) {
                if ( dc.getCurrent() > 1 ) {
                    return getItem().getShortDesc() + sb.toString() + ", empty)";
                }
                else {
                    return getItem().getShortDesc() + " (empty)";
                }
            }
            else {
                String leftovers = CSConstantsFood.getDrinkableLeftovers( dc.getPortion(), dc.getMaxPortion() );
                String fluidName = CSConstantsFood.getFluidName( dc.getFluidContent() );
                if ( dc.getCurrent() > 1 ) {
                    return getItem().getShortDesc() + sb.toString() + ", " + leftovers + " " + fluidName + ")" + dc.getPortion();
                }
                else {
                    return getItem().getShortDesc() + sb.toString() + leftovers + " " + fluidName + ")" + dc.getPortion();
                }
            }
        }

        if ( isStackable() ) {
            if ( getItem().getStack().getCurrent() > 1 ) {
                return getItem().getShortDesc() + " (x" + getAmountController().getCurrent() + ")";
            }
        }

        return getItem().getShortDesc();
    }

    public String getLongDesc() {
        if ( isEatable() ) {
            FoodController fc = (FoodController) getAmountController();
            String leftovers = CSConstantsFood.getEdibleLeftoversLabel( fc.getPortion(), fc.getMaxPortion() );
            if ( fc.getCurrent() == 1 ) {
                return getItem().getLongDesc() + " (" + leftovers + ")" + fc.getPortion();
            }
            else {
                return getItem().getLongDesc() + " (x" + fc.getCurrent() + ", " + leftovers + ")" + fc.getPortion();
            }
        }

        if ( isDrinkable() ) {
            DrinkController dc = (DrinkController) getAmountController();
            StringBuilder sb = new StringBuilder( " (" );
            if ( dc.getCurrent() > 1 ) {
                sb.append( "x" + dc.getCurrent() );
            }
            if ( dc.hasNoPortionLeft() ) {
                if ( dc.getCurrent() > 1 ) {
                    return getItem().getLongDesc() + sb.toString() + ", empty)";
                }
                else {
                    return getItem().getLongDesc() + " (empty)";
                }
            }
            else {
                String leftovers = CSConstantsFood.getDrinkableLeftovers( dc.getPortion(), dc.getMaxPortion() );
                String fluidName = CSConstantsFood.getFluidName( dc.getFluidContent() );
                if ( dc.getCurrent() > 1 ) {
                    return getItem().getLongDesc() + sb.toString() + ", " + leftovers + " " + fluidName + ")" + dc.getPortion();
                }
                else {
                    return getItem().getLongDesc() + sb.toString() + leftovers + " " + fluidName + ")" + dc.getPortion();
                }
            }
        }

        if ( isStackable() ) {
            if ( getAmountController().getCurrent() > 1 ) {
                return getItem().getLongDesc() + " (x" + getAmountController().getCurrent() + ")";
            }
        }

        return getItem().getLongDesc();
    }

    public ItemController spawnFromSetOfEmptyContainers( Fluid fluid, int initialAmount ) {
        if ( !isDrinkable() ) {
            throw new IllegalStateException( "Only applies to drinkable items." );
        }

        ItemController newContainer = getChatoServer().getItemHandler().copyItemController( this );
        ( (DrinkController) newContainer.getAmountController() ).setPortion( initialAmount );
        newContainer.getAmountController().setCurrent( 1 );
        getAmountController().decrease( 1 );
        ( (DrinkController) getAmountController() ).setFluidContent( fluid );

        return newContainer;
    }

    public ItemController spawnFromSetOfNonEmptyContainers() {
        if ( !isDrinkable() ) {
            throw new IllegalStateException( "Only applies to drinkable items." );
        }

        ItemController newContainer = getChatoServer().getItemHandler().copyItemController( this );
        newContainer.getAmountController().setCurrent( 1 );
        getAmountController().decrease( 1 );
        ( (DrinkController) newContainer.getAmountController() ).setPortion( 0 );
        ( (DrinkController) getAmountController() ).setToMaxPortion();

        return newContainer;
    }

    public void junk() {
        getContainerController().junk( this );
    }

    public Item getItem() {
        return item;
    }

    public ChatoServer getChatoServer() {
        return chatoServer;
    }

    public KeywordsController getKeywordsController() {
        return keywordsController;
    }

    public BoxInventoryController getInventoryController() {
        return (BoxInventoryController) inventoryController;
    }

    public InventoryController getContainerController() {
        return containerController;
    }

    public void setContainerController( InventoryController containerController ) {
        this.containerController = containerController;
    }

    public LockController getLockController() {
        return lockController;
    }

    public AmountController getAmountController() {
        return amountController;
    }

    public WearController getWearController() {
        return wearController;
    }

    public boolean acceptsWearLoc( WearLoc wearLoc ) {
        return getWearController().canBeWornIn( wearLoc );
    }

    public int computeWeight() {
        if ( isDrinkable() ) {
            return getItem().getW() * getAmountController().getCurrent() + ( (DrinkController) getAmountController() ).computeWeight();
        }
        if ( isEatable() ) {
            int wholePart = ( getAmountController().getCurrent() - 1 ) * getItem().getW();
            float portionRatio = ( (FoodController) getAmountController() ).getPortionRatio();
            int portionPart = (int) ( portionRatio * (float) getItem().getW() );
            return wholePart + portionPart;
        }
        if ( isStackable() ) {
            return getItem().getW() * getAmountController().getCurrent();
        }
        if ( isStorage() ) {
            return getItem().getW() + getInventoryController().computeWeight();
        }

        return getItem().getW();
    }

}
